// One of the biggest hurdles to understanding functional programs when coming
// from an imperative background is the shift in thinking. Imperative programs
// describe how to do something, whereas declarative programs describe what to
// do. Let’s sum the numbers from 1 to 10 to show this.
fn main() {
    {
        // Imperative.
        //
        // With imperative programs, we have to play compiler to see what is
        // happening. Here, we start with a sum of 0. Next, we iterate through
        // the range from 1 to 10. Each time through the loop, we add the
        // corresponding value in the range. Then we print it out.
        //
        // This is how most of us start out programming. We learn that a program
        // is a set of steps.
        let mut sum = 0;
        for i in 1..11 {
            sum += i;
        }
        println!("{sum}");
    }

    println!();

    #[allow(clippy::unnecessary_fold)]
    {
        // Declarative.
        //
        // Whoa! This is really different! What’s going on here? Remember that
        // with declarative programs we are describing what to do, rather than
        // how to do it. fold is a function that composes functions. The name
        // is a convention from Haskell.
        //
        // Here, we are composing functions of addition (this closure: |a, b|
        // a + b) with a range from 1 to 10. The 0 is the starting point, so a
        // is 0 at first. b is the first element of the range, 1. 0 + 1 = 1 is
        // the result. So now we fold again, with a = 1, b = 2 and so 1 + 2 = 3
        // is the next result. This process continues until we get to the last
        // element in the range, 10.
        println!("{}", (1..11).fold(0, |a, b| a + b));
        println!("{}", (1..11).sum::<i32>());
    }
}
